#ifndef MEMBER_CPP
#define MEMBER_CPP
#include "Member.h"

Member::Member(std::string name_, std::string address_, std::string type_, std::string contacts_, const std::vector<Loaning*> &booksBorrowed_) : name(name_), address(address_), type(type_), contacts(contacts_), booksBorrowed(booksBorrowed_)
{
	for (const auto &e : name)
	{
		if (isupper(e))
			id += e;
	}
	id += address[0];
	id += type[0];
}

Member::~Member()
{
	for (Loaning* l : booksBorrowed)
	{
		delete l;
	}
}

bool Student::Borrow(Book *book, Date& dateOfBegin_)
{
	//Nem lépte-e túl a limitet, amennyi könyvet kivehet
	if (booksBorrowed.size() == 5)
	{
		std::cout << "\nThe member can't borrow more books.";
		std::cin.get();
		return false;
	}
	//A visszahozás dátumának kiszámolása
	Date dateOfReturn = dateOfBegin_.AddDays(60);
	book->AddBorrower(this);

	Loaning* loaning = new Loaning(dateOfBegin_, book->GetID(), dateOfReturn);
	booksBorrowed.push_back(loaning);
	return true;
}

bool Teacher::Borrow(Book *book, Date& dateOfBegin_)
{
	//A tanároknál nincs limitellenőrzés, tetszőleges számú könyvet kivehetnek

	//A visszahozás dátumának kiszámolása
	Date dateOfReturn = dateOfBegin_.AddDays(365);
	book->AddBorrower(this);

	Loaning* loaning = new Loaning(dateOfBegin_, book->GetID(), dateOfReturn);
	booksBorrowed.push_back(loaning);
	return true;
}

bool OtherUnivCitizen::Borrow(Book *book, Date& dateOfBegin_)
{
	//Nem lépte-e túl a limitet, amennyi könyvet kivehet
	if (booksBorrowed.size() == 4)
	{
		std::cout << "\nThe member can't borrow more books.";
		std::cin.get();
		return false;
	}
	//A visszahozás dátumának kiszámolása
	Date dateOfReturn = dateOfBegin_.AddDays(30);
	book->AddBorrower(this);

	Loaning* loaning = new Loaning(dateOfBegin_, book->GetID(), dateOfReturn);
	booksBorrowed.push_back(loaning);
	return true;
}

bool Other::Borrow(Book *book, Date& dateOfBegin_)
{
	//Nem lépte-e túl a limitet, amennyi könyvet kivehet
	if (booksBorrowed.size() == 2)
	{
		std::cout << "\nThe member can't borrow more books.";
		std::cin.get();
		return false;
	}
	//A visszahozás dátumának kiszámolása
	Date dateOfReturn = dateOfBegin_.AddDays(14);
	book->AddBorrower(this);

	Loaning* loaning = new Loaning(dateOfBegin_, book->GetID(), dateOfReturn);
	booksBorrowed.push_back(loaning);
	return true;
}

bool Member::ReturnBook(Book *book, Date& dateOfReturn_)
{
	//Megvizsgáljuk, hogy időben hozta-e vissza a könyvet
	bool isBeforeDueDate = true;
	Date dueDate; //megkeressük a dátumot, ameddig vissza kell hozni a könyvet

	//Tudjuk hogy van a booksBorrowed vektorban ilyen könyv, a menüben megvizsgáltuk
	//Töröljük a tag kölcsönzött könyvei közül, amit visszahozott
	bool found = false;
	for (auto it = booksBorrowed.begin(); it != booksBorrowed.end() && !found;)
	{
		if ((*it)->bookID == book->GetID())
		{
			//Ha megtaláltuk a keresett könyv ID-jét, akkor törlés előtt jegyezzük meg egy változóba a kölcsönzés végét.
			dueDate = (*it)->dateOfReturn;
			it = booksBorrowed.erase(it);
			found = true;
		}
		else 
			++it;
	}

	isBeforeDueDate = dueDate.IsBeforeDueDate(dateOfReturn_);
	//Töröljük a könyv kölcsönzői közül a tagot, tudjuk, hogy benne van
	book->RemoveBorrower(this);
	std::cin.get();

	return isBeforeDueDate;
}


Date::Date(std::string str)
{
	year = str.substr(0, str.find('.'));

	str = str.substr(str.find('.') + 1);
	month = str.substr(0, str.find('.'));

	str = str.substr(str.find('.') + 1);
	day = str.substr(0, str.find('.'));
}

bool Date::IsBeforeDueDate (Date &dateOfReturn_) const
{
	//a lexikografikus rendezés pont jó lesz
	std::string dueDate, dateOfReturn;
	dueDate += year;
	dueDate += month;
	dueDate += day;
	dateOfReturn += dateOfReturn_.year;
	dateOfReturn += dateOfReturn_.month;
	dateOfReturn += dateOfReturn_.day;

	return dateOfReturn <= dueDate;
}

bool Date::IsValidDate () const
{
	int nYear = atoi(year.c_str());
	int nMonth = atoi(month.c_str());
	int nDay = atoi(day.c_str());
	bool isLeapYear = ((nYear % 4 == 0 && nYear % 100 != 0) || (nYear % 400 == 0));

	if (nMonth == 2 && nDay == 29)
		return isLeapYear;

	if (nMonth == 2)
		return (1 <= nDay && nDay <= 28);

	if (nMonth == 4 || nMonth == 6 || nMonth == 9 || nMonth == 11)
		return (1 <= nDay && nDay <= 30);

	if (nMonth == 1 || nMonth == 3 || nMonth == 5 || nMonth == 7 || nMonth == 8 || nMonth == 10 || nMonth == 12)
		return (1 <= nDay && nDay <= 31);

	return false;
}

Date Date::AddDays (int days) const
{
	//tm structtá alakítjuk a dátumot
	struct tm t = {0};
	t.tm_mday = atoi(day.c_str());
	t.tm_mon = atoi(month.c_str())-1;
	t.tm_year = atoi(year.c_str())-1900;

	time_t timeSinceEpoch1970 = mktime(&t); //másodpercekké alakítjuk a tm structot

	struct tm *tmaa = localtime(&timeSinceEpoch1970); //egy másik structot hozunk létre, ebben fogjuk eltolni a megadott nappal a dátumot
	tmaa->tm_mday += days; //eltoljuk a megadott nappal
	time_t newDate = mktime(tmaa); //másodpercekké alakítjuk az eltolt dátumot

	//newDatet kinyerjük struct alakba másodperc alakból, így már értékül tudjuk adni az attribútumoknak
	struct tm *NewDateAsStruct;
	NewDateAsStruct = localtime (&newDate);

	std::string year, month, day;
	//int->std::string konverziók
	std::ostringstream sstr;
	sstr << NewDateAsStruct->tm_year+1900;
	year = sstr.str();

	sstr.str("");
	if (NewDateAsStruct->tm_mon+1 < 10)
		sstr << "0";
	sstr << NewDateAsStruct->tm_mon+1;
	month = sstr.str();

	sstr.str("");
	if (NewDateAsStruct->tm_mday < 10)
		sstr << "0";
	sstr << NewDateAsStruct->tm_mday;
	day = sstr.str();

	Date date(year,month,day);
	return date;
}

#endif